package com.idea.relax.log.config;

import com.idea.relax.log.api.custom.ICustomFieldsProvider;
import com.idea.relax.log.aspect.ApiLogAspect;
import com.idea.relax.log.aspect.RequestLogAspect;
import com.idea.relax.log.listener.*;
import com.idea.relax.log.logger.RelaxLogger;
import com.idea.relax.log.props.RelaxLogProperties;
import com.idea.relax.log.service.IGeneralLogService;
import com.idea.relax.log.service.IRelaxLogService;
import com.idea.relax.log.service.IApiLogService;
import com.idea.relax.log.service.IErrorLogService;
import com.idea.relax.log.support.spel.RelaxExpressionEvaluator;
import com.idea.relax.log.support.spel.RelaxExpressionParser;
import com.idea.relax.log.api.callback.FailureCallback;
import com.idea.relax.log.thread.RelaxLoggingThreadPoolManager;
import com.idea.relax.log.api.callback.RelaxFailureCallbackHandler;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.Order;


/**
 * @className: RelaxLogAutoConfiguration
 * @description: RelaxLog的自动配置类
 * @author: salad
 * @date: 2022/10/1
 **/
@Order
@Configuration(
        proxyBeanMethods = false
)
@ConditionalOnWebApplication
@ConditionalOnProperty(
        value = {RelaxLogProperties.PREFIX + RelaxLogProperties.ENABLED},
        havingValue = "true"
)
@EnableConfigurationProperties({RelaxLogProperties.class})
public class RelaxLogAutoConfiguration {

    @Bean("relaxLogger")
    @ConditionalOnMissingBean(name = "relaxLogger")
    public RelaxLogger relaxLogger() {
        return new RelaxLogger();
    }

    @Bean(name = "relaxExpressionParser")
    @ConditionalOnMissingBean(name = "relaxExpressionParser")
    @ConditionalOnProperty(prefix = RelaxLogProperties.ApiLog.PREFIX, name = "enabled", havingValue = "true")
    public RelaxExpressionParser relaxExpressionParser() {
        return new RelaxExpressionEvaluator();
    }


    @Bean(name = "apiLogPointcutAdvisor")
    @ConditionalOnProperty(prefix = RelaxLogProperties.ApiLog.PREFIX, name = "enabled", havingValue = "true")
    public DefaultPointcutAdvisor apiLogPointcutAdvisor(RelaxLogProperties properties) {
        ApiLogAspect interceptor = new ApiLogAspect(properties);
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(properties.getApiLog().getPointcutExp());
        advisor.setPointcut(pointcut);
        advisor.setAdvice(interceptor);
        return advisor;
    }


    @Bean("apiLogListener")
    @ConditionalOnProperty(prefix = RelaxLogProperties.ApiLog.PREFIX, name = "enabled", havingValue = "true")
    public ApiLogListener apiLogListener(ObjectProvider<IApiLogService> apiLogServices,
                                         ObjectProvider<IRelaxLogService> relaxLogServices,
                                         RelaxExpressionParser relaxExpressionParser,
                                         RelaxLoggingThreadPoolManager threadPoolManager,
                                         RelaxFailureCallbackHandler failureCallbackHandler) {
        IApiLogService apiLogService = apiLogServices.getIfAvailable();
        IRelaxLogService relaxLogService = relaxLogServices.getIfAvailable();
        return new ApiLogListener(apiLogService, relaxLogService,
                relaxExpressionParser, threadPoolManager, failureCallbackHandler);
    }


    @Bean(name = "requestLogPointcutAdvisor")
    @ConditionalOnProperty(prefix = RelaxLogProperties.RequestLog.PREFIX, name = "enabled", havingValue = "true")
    public DefaultPointcutAdvisor requestLogPointcutAdvisor(RelaxLogProperties properties,ObjectProvider<ICustomFieldsProvider> objectProvider) {
        RequestLogAspect interceptor = new RequestLogAspect(properties,objectProvider);
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(properties.getRequestLog().getPointcutExp());
        advisor.setPointcut(pointcut);
        advisor.setAdvice(interceptor);
        return advisor;
    }

    @Bean("errorLogListener")
    @ConditionalOnProperty(prefix = RelaxLogProperties.ErrorLog.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
    public ErrorLogListener errorLogListener(ObjectProvider<IErrorLogService> errorLogServices,
                                             ObjectProvider<IRelaxLogService> relaxLogServices,
                                             RelaxLogProperties properties,
                                             RelaxLoggingThreadPoolManager threadPoolManager,
                                             RelaxFailureCallbackHandler failureCallbackHandler) {
        IErrorLogService errorLogService = errorLogServices.getIfAvailable();
        IRelaxLogService relaxLogService = relaxLogServices.getIfAvailable();
        return new ErrorLogListener(errorLogService, relaxLogService,
                properties, threadPoolManager, failureCallbackHandler);
    }

    @Bean("generalLogListener")
    public GeneralLogListener generalLogListener(ObjectProvider<IGeneralLogService> generalLogServices,
                                                 ObjectProvider<IRelaxLogService> relaxLogServices,
                                                 RelaxLoggingThreadPoolManager threadPoolManager,
                                                 RelaxFailureCallbackHandler failureCallbackHandler) {
        IGeneralLogService generalLogService = generalLogServices.getIfAvailable();
        IRelaxLogService relaxLogService = relaxLogServices.getIfAvailable();
        return new GeneralLogListener(generalLogService, relaxLogService,
                threadPoolManager, failureCallbackHandler);
    }

    @Bean("webServerStartedAfterListener")
    public WebServerStartedAfterListener webServerStartedAfterListener(RelaxLogProperties properties) {
        return new WebServerStartedAfterListener(properties);
    }


    @Bean("relaxFailureCallbackHandler")
    @ConditionalOnProperty(prefix = RelaxLogProperties.AsyncThread.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
    public RelaxFailureCallbackHandler relaxFailureCallbackHandler(ObjectProvider<FailureCallback> objectProvider) {
        return new RelaxFailureCallbackHandler(objectProvider);
    }

    @Bean("relaxLoggingThreadPoolExecutor")
    @ConditionalOnMissingBean(
            name = {"relaxLoggingThreadPoolExecutor"}
    )
    @ConditionalOnProperty(prefix = RelaxLogProperties.AsyncThread.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
    public RelaxLoggingThreadPoolManager relaxLoggingThreadPoolManager(RelaxLogProperties properties) {
        return new RelaxLoggingThreadPoolManager(properties.getAsyncStorage());
    }




}
